/**
 * Created by hanj on 2019/11/4 14:35
 */
package geektime.demo.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Optional;

/**
 * aop切面
 */
@Aspect
@Controller
@Lazy(false)
public class PermissionAop {

    /**
     * 定义一个切点
     * <p>
     * 通过匹配注解的方式切进来,所有被GetMapping 和 PostMapping 注解的方法都会通过这个切点进来
     */
    @Pointcut(value = "@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void permissionAop() {
    }

    ;

    /**
     * aop增强
     *
     * @return
     */
    @Around(value = "permissionAop()")
    private Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("@Around:开始校验权限..");
        Signature sig = joinPoint.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Method currentMethod = msig.getMethod();


        //获取GetMapping注解中的路径
//        String methodMapping = null;
//        GetMapping methodGetMapping = currentMethod.getAnnotation(GetMapping.class);
//        if (methodGetMapping != null && methodGetMapping.value() != null && methodGetMapping.value().length > 0) {
//            methodMapping = methodGetMapping.value()[0];
//        }
        //JDK8新特性
        GetMapping methodGetMapping = currentMethod.getAnnotation(GetMapping.class);
        String methodMapping = Optional.ofNullable(methodGetMapping)
                .filter(GetMapping -> methodGetMapping.value().length > 0)
                .map(GetMapping -> methodGetMapping.value()[0]).orElseGet(null);

        //访问目标方法的参数：
//        String userType = "";
//        Object[] args = joinPoint.getArgs();
//        if (args != null && args.length > 0 && args[0].getClass() == String.class) {
//            userType = (String) args[0];
//        }
        //JDK8新特性
        Object[] args = joinPoint.getArgs();
        String userType = (String) Optional.ofNullable(args)
                .filter(Object -> args.length > 0)
                .map(Object -> args[0]).orElseGet(() -> "");

        //接口需要验证管理员权限
        if (!StringUtils.isEmpty(methodMapping) && methodMapping.startsWith("/hello")) {
            if (userType.equals("admin")) {
                joinPoint.proceed();
                System.out.println("@Around：满足权限...");
                return "ok";
            } else {
                System.out.println("@Around：不满足权限...");
                return "无权限访问";
            }
        }
        return joinPoint.proceed();

        //实现全局权限访问
//        return Optional.ofNullable(methodMapping)
//                .filter(Boolean -> methodMapping.startsWith("hello"))
//                .map(Object -> {
//                    try {
//                        return joinPoint.proceed();
//                    } catch (Throwable throwable) {
//                        throwable.printStackTrace();
//                    }
//                    return null;
//                }).orElseGet(() -> {
//                    return Optional.ofNullable(methodMapping)
//                            .filter(Boolean -> userType.equals("admin"))
//                            .map(m -> {
//                                        try {
//                                            joinPoint.proceed();
//                                        } catch (Throwable throwable) {
//                                            throwable.printStackTrace();
//                                        }
//                                        System.out.println("@Around：满足权限...");
//                                        return "ok";
//                                    }
//                            ).orElseGet(() -> {
//                                System.out.println("@Around：不满足权限...");
//                                return "无权限访问";
//                            });
//                });
    }

    @Before("permissionAop()")
    public void permissionCheck(JoinPoint point) {
        System.out.println("@Before：开始权限检查...");
        System.out.println("@Before：目标方法为：" +
                point.getSignature().getDeclaringTypeName() +
                "." + point.getSignature().getName());
        System.out.println("@Before：参数为：" + Arrays.toString(point.getArgs()));
        System.out.println("@Before：被织入的目标对象为：" + point.getTarget());
    }

    @AfterReturning(pointcut = "permissionAop()",
            returning = "returnValue")
    public void log(JoinPoint point, Object returnValue) {
        System.out.println("@AfterReturning：开始记录返回值...");
        System.out.println("@AfterReturning：目标方法为：" +
                point.getSignature().getDeclaringTypeName() +
                "." + point.getSignature().getName());
        System.out.println("@AfterReturning：参数为：" +
                Arrays.toString(point.getArgs()));
        System.out.println("@AfterReturning：返回值为：" + returnValue);
        System.out.println("@AfterReturning：被织入的目标对象为：" + point.getTarget());

    }

    @After("permissionAop()")
    public void releaseResource(JoinPoint point) {
        System.out.println("@Before：结束权限检查...");
    }

}
